package com.dding.cms.base.dao.impl;

import static com.dding.cms.base.web.ActionConstants.DEFAULT_CHANGE_FIELDS;
import static com.dding.cms.base.web.ActionConstants.UPDATE_DATA_MAP;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.StringTokenizer;

import org.dding.core.util.StringUtils;
import org.javalite.activejdbc.Association;
import org.javalite.activejdbc.Model;
import org.javalite.activejdbc.associations.BelongsToAssociation;

import com.dding.cms.base.entity.Content;
import com.dding.cms.base.entity.ContentAttr;
import com.dding.cms.base.web.widget.IWidgetContext;
import com.dding.cms.base.web.widget.IWidgetHandler;
import com.dding.cms.base.web.widget.WidgetContext;
import com.dding.cms.base.web.widget.WidgetUtils;

public class ContentUpdateDaoHandler extends
		AbstractDaoHandler<String[], String[]> {

	private static Set<String> columns;
	private static Set<String> changeFields = new HashSet<String>();

	@Override
	public Map<String, String[]> handleField(Map<String, String[]> dataMap,
			Model model) throws Throwable {

		columns = WidgetUtils.getContentColumns();

		StringTokenizer token = new StringTokenizer(
				dataMap.get(DEFAULT_CHANGE_FIELDS)[0], ",");
		while (token.hasMoreTokens()) {
			changeFields.add(token.nextToken());
		}

		StringBuilder updates = new StringBuilder();
		List<Object> fieldparams = new ArrayList<Object>();
		boolean ok = false;

		for (Entry<String, String[]> entry : dataMap.entrySet()) {

			if (changeFields.contains(entry.getKey())) {
				if (handleColumnUpdateField(entry.getKey(),
						entry.getValue()[0], updates, fieldparams)) {
					changeFields.remove(entry.getKey());
					ok = true;
				}
			}
		}
		if (ok) {
			fieldparams.add(dataMap.get("content_id")[0]);
			Content.update(updates.substring(0, updates.length() - 1),
					"content_id=?", fieldparams.toArray());
		}
		return dataMap;
	}

	@Override
	public Map<String, String[]> handleAssocaition(
			Map<String, String[]> dataMap, List<Model> list, Model model)
			throws Throwable {

		@SuppressWarnings("unchecked")
		List<Association> associations = Content.associations();
		for (Association association : associations) {
			if (association instanceof BelongsToAssociation) {
				continue;
			}
			handleInternalAssociation(association.getTarget(), dataMap);
		}
		return dataMap;
	}

	private void handleInternalAssociation(String targetTable,
			Map<String, String[]> dataMap) {

		IWidgetHandler handler = controller.getWidgetByTable(targetTable);
		if (handler == null)
			return;
		Map<String, Object> data = new HashMap<String, Object>();
		data.put(DEFAULT_CHANGE_FIELDS, changeFields);
		data.put(UPDATE_DATA_MAP, dataMap);

		IWidgetContext widgetContext = new WidgetContext(data);
		handler.handleUpdateAssociation(widgetContext);
	}

	@Override
	public Map<String, String[]> handleExtAttr(Map<String, String[]> dataMap,
			List<Model> list, Model model) throws Throwable {

		StringBuilder updates = new StringBuilder();

		List<Object[]> fieldparams = new ArrayList<Object[]>();
		String id = dataMap.get("content_id")[0];
		for (String field : changeFields) {
			String[] value = dataMap.get(field);
			if (value != null && value.length != 0)
				handleAttrUpdateField(field, value[0], id, updates, fieldparams);
		}

		String query = "attr_value = ?";
		String conditions = "attr_name = ? and content_id = ?";
		ContentAttr.update(query, conditions,
				fieldparams.toArray(new Object[0][0]));

		changeFields.clear();
		return dataMap;

	}

	private boolean handleColumnUpdateField(String key, String value,
			StringBuilder updates, List<Object> fieldparams) {

		String[] name = WidgetUtils.parserName(key);

		if (name != null && name.length == 1) {

			if (!columns.contains(key)) {
				return false;
			}

			if ("content_id".equals(key))
				return false;
			handleColumnFieldWithoutHandler(key, value, updates, fieldparams);

		} else if (name != null && name.length == 2) {

			if (!columns.contains(name[0])) {
				return false;
			}

			IWidgetHandler handler = controller.getWidgetByTypeAndName(name[1],
					name[0]);
			if (handler != null) {
				if (columns.contains(name[0])) {
					Map<String, Object> map = new HashMap<String, Object>();
					map.put(name[0], value);
					IWidgetContext widgetContext = new WidgetContext(map);
					Object col = handler.handleUpdateField(widgetContext);
					updates.append(name[0] + "=?");
					updates.append(",");
					fieldparams.add(col);
				}
			} else {
				handleColumnFieldWithoutHandler(key, value, updates,
						fieldparams);
			}
		}
		return true;
	}

	private boolean handleAttrUpdateField(String key, String value, String id,
			StringBuilder updates, List<Object[]> fieldparams) {

		String[] name = WidgetUtils.parserName(key);

		if (name != null && name.length == 1) {

			if (columns.contains(key)) {
				return false;
			}

			if ("content_id".equals(key))
				return false;
			handleAttrFieldWithoutHandler(key, value, id, updates, fieldparams);

		} else if (name != null && name.length == 2) {

			if (columns.contains(name[0])) {
				return false;
			}

			IWidgetHandler handler = controller.getWidgetByTypeAndName(name[1],
					name[0]);
			if (handler != null) {
				Map<String, Object> map = new HashMap<String, Object>();
				map.put(name[0], value);
				IWidgetContext widgetContext = new WidgetContext(map);
				Object col = handler.handleUpdateField(widgetContext);
				handleAttrFieldWithoutHandler(name[0], col, id, updates,
						fieldparams);
			} else {
				handleAttrFieldWithoutHandler(key, value, id, updates,
						fieldparams);
			}
		}
		return true;
	}

	private void handleColumnFieldWithoutHandler(String key, String value,
			StringBuilder updates, List<Object> params) {

		updates.append(key + "=?");
		updates.append(",");
		params.add(StringUtils.isEmpty(value) ? null : value);
	}

	private void handleAttrFieldWithoutHandler(String key, Object value,
			String id, StringBuilder updates, List<Object[]> fieldparams) {

		Object[] array = new Object[3];
		array[0] = value;
		array[1] = key;
		array[2] = id;
		fieldparams.add(array);
	}
}
